﻿using System;
using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using KL.UFrame.Api.Extensions;
using KL.UFrame.Core.Configuration;
using KL.UFrame.Core.Result;
using KL.UFrame.Data.Business;
using KL.UFrame.Data.Entities;
using KL.UFrame.Data.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;

namespace KL.UFrame.Api.ApiControllers
{
    [RoutePrefix("api/Account")]
    public class AccountController : K9ApiBaseController
    {
        private ApplicationUserManager _userManager;
        private IAccountBusiness _business;
        private IEmailBusiness _emailService;
        public AccountController(IAccountBusiness business, IEmailBusiness emailBusiness)
        {
            _business = business;
            _emailService = emailBusiness;
        }

        public ApplicationUserManager UserManager
        {
            get
            {
                return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
            private set
            {
                _userManager = value;
            }
        }
        
        #region  User's Api
        // GET api/Account/UserInfo
        [Route("UserInfo")]
        public async Task<ResultMessage<AccountInfoModel>> GetUserInfo()
        {
            return new ResultMessage<AccountInfoModel>(await _business.GetUserInfoAsync(User.Identity.Name));
        }

        // POST api/Account/Logout
        [Route("Logout")]
        public IHttpActionResult Logout()
        {
            Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
            return Ok();
        }
        

        // POST api/Account/ChangePassword
        [Route("ChangePassword")]
        public async Task<ResultMessage> ChangePassword(ChangePasswordBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return ModelState.ToResultMessage();
            }

            IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
                model.NewPassword);

            if (!result.Succeeded)
            {
                return new ResultMessage(-2, result.Errors.First());
            }

            return new ResultMessage();
        }

        [AllowAnonymous]
        [HttpPost]
        [Route("ForgotPwd")]
        public async Task<ResultMessage> ForgotPwd(string userName, string email)
        {
            var bMatch = await _business.ValidateUserWithEmailAsync(userName, email);
            if (!bMatch) return new ResultMessage(-1, "用户名与Email未绑定");
            var code = await _emailService.SendVerifyCodeAsync(email);
            return new ResultMessage();
        }
        // POST api/Account/SetPassword
        [AllowAnonymous]
        [Route("SetPassword")]
        public async Task<ResultMessage> SetPassword(SetPasswordBindingModel model)
        {
            var verifyCode = _emailService.GetValidateCode(model.Email);
            if (verifyCode == null || verifyCode != model.Code)
            {
                return new ResultMessage(-3, "验证码不正确");
            }
            if (!ModelState.IsValid)
            {
                return ModelState.ToResultMessage();
            }
            var user = await UserManager.FindByNameAsync(model.Phone);
            var token = UserManager.GeneratePasswordResetToken(user.Id);
            IdentityResult result = await UserManager.ResetPasswordAsync(user.Id, token, model.NewPassword);

            if (!result.Succeeded)
            {
                return new ResultMessage(-2, result.Errors.First());
            }

            return new ResultMessage();
        }


        // GET api/Account/AuthStatus
        [Route("AuthStatus")]
        public IHttpActionResult GetAuthStatus()
        {
            if (User.Identity.IsAuthenticated && !string.IsNullOrEmpty(User.Identity.Name))
                return Ok();
            return Unauthorized(Request.Headers.Authorization);
        }

        static Regex _forbidenRegex = new Regex(AppConfiguration.ForbidenRegexString);

        /// <summary>
        /// 更新姓名
        /// </summary>
        /// <param name="newName"></param>
        /// <returns></returns>
        public async Task<ResultMessage> PostName(string newName)
        {
            if (string.IsNullOrEmpty(newName)
                || !_forbidenRegex.IsMatch(newName))
            {
                return new ResultMessage(-1, "姓名字符不合法");
            }

            await _business.UpdateNameAsync(User.Identity.GetUserId(), newName);
            return new ResultMessage();
        }
        /// <summary>
        /// 更新Email
        /// </summary>
        /// <param name="newEmail"></param>
        /// <param name="code">发送邮件中的验证码</param>
        /// <returns></returns>
        public async Task<ResultMessage> PostEmail(string newEmail, string code)
        {
            var userId = User.Identity.GetUserId();

            return await _business.UpdateEmailAsync(userId, newEmail);
        }

        /// <summary>
        /// 发送Email验证码
        /// </summary>
        /// <param name="email"></param>
        /// <returns></returns>
        [Route("Verify")]
        public async Task<ResultMessage> PostEmail(string email)
        {
            var code = await _emailService.SendVerifyCodeAsync(email);
            if (code <= 0) return new ResultMessage(-1, "发送验证失败");
            return new ResultMessage();
        }

        /// <summary>
        /// 更新头像
        /// </summary>
        /// <param name="headUrl"></param>
        /// <returns></returns>
        public async Task<ResultMessage> Post(string headUrl)
        {
            await _business.UpdateHeadAsync(User.Identity.GetUserId(), headUrl);
            return new ResultMessage();
        }

        #endregion
        
        
        protected override void Dispose(bool disposing)
        {
            if (disposing && _userManager != null)
            {
                _userManager.Dispose();
                _userManager = null;
            }

            base.Dispose(disposing);
        }

        #region 帮助程序

        private IAuthenticationManager Authentication
        {
            get { return Request.GetOwinContext().Authentication; }
        }

        private static class RandomOAuthStateGenerator
        {
            private static RandomNumberGenerator _random = new RNGCryptoServiceProvider();

            public static string Generate(int strengthInBits)
            {
                const int bitsPerByte = 8;

                if (strengthInBits % bitsPerByte != 0)
                {
                    throw new ArgumentException("strengthInBits 必须能被 8 整除。", nameof(strengthInBits));
                }

                int strengthInBytes = strengthInBits / bitsPerByte;

                byte[] data = new byte[strengthInBytes];
                _random.GetBytes(data);
                return HttpServerUtility.UrlTokenEncode(data);
            }
        }

        #endregion
    }
}
